package com.duoduo.common.util.interptor;


import com.duoduo.common.api.constants.Constant;
import com.duoduo.common.api.constants.LogConstant;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.Statement;
import java.util.Properties;

@Intercepts({@Signature(type = StatementHandler.class, method = "query", args = {Statement.class, ResultHandler.class}),
    @Signature(type = StatementHandler.class, method = "update", args = {Statement.class}),
    @Signature(type = StatementHandler.class, method = "batch", args = {Statement.class})})
public class SqlTracerInterceptor implements Interceptor {

	private static final Logger logger = LoggerFactory.getLogger(SqlTracerInterceptor.class);
	
	/* 要进行拦截的时候要执行的方法
	 * @see org.apache.ibatis.plugin.Interceptor#intercept(org.apache.ibatis.plugin.Invocation)
	 */
	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		SqlTracer sqlTracer = null;
		Object result = null;
		Throwable th = null;
		try{
			Object target = invocation.getTarget();
	        StatementHandler statementHandler = (StatementHandler) target;
	        BoundSql boundSql = statementHandler.getBoundSql();
	        String sql = boundSql.getSql(); //获取sql
	        Object obj = boundSql.getParameterObject();
	        sqlTracer = ExtensionLoader.getExtensionLoader(SqlTracer.class).getExtension(Constant.TRACER_SQL_CLIENT_NAME);
	        sqlTracer.invoke(sql, obj);
		} catch (Throwable t){
			// 捕获异常，记录日志，不要影响业务执行
    		logger.error(LogConstant.TRACER + " sql tracer interceptor error", t);
		}
        try {
            result = invocation.proceed(); //sql运行
            return result;
        } catch (Throwable t) {
        	th = t;
            throw t;
        } finally {
        	if(sqlTracer != null){
        		sqlTracer.invokeAfterClient(result, th);
			}
        }
	}

	/* 决定是否要进行拦截进而决定要返回一个什么样的目标对象
	 * @see org.apache.ibatis.plugin.Interceptor#plugin(java.lang.Object)
	 */
	@Override
	public Object plugin(Object target) {
		return Plugin.wrap(target, this);
	}

	/* 用于在Mybatis配置文件中指定一些属性的
	 * @see org.apache.ibatis.plugin.Interceptor#setProperties(java.util.Properties)
	 */
	@Override
	public void setProperties(Properties properties) {
		
	}

}
